using System.Net;
using Amazon.SimpleDB;
using Coditate.Savant.TestSupport;
using NUnit.Framework;
using Rhino.Mocks;
using AmazonAttribute=Amazon.SimpleDB.Model.Attribute;

namespace Coditate.Savant.Core
{
    [TestFixture]
    public class DomainCreatingSavantTest
    {
        private ISimpleSavant2Ex decoratedSavant;
        private AmazonSimpleDBException domainMissingException;
        private AmazonSimpleDB simpleDb;
        private DomainCreatingSavant domainSavant;

        [SetUp]
        public void SetUp()
        {
            simpleDb = MockRepository.GenerateMock<AmazonSimpleDB>();
            decoratedSavant = MockRepository.GenerateMock<ISimpleSavant2Ex>();
            decoratedSavant.Expect(x => x.SimpleDB).Return(simpleDb).Repeat.Any();

            domainMissingException = new AmazonSimpleDBException("", HttpStatusCode.OK, "NoSuchDomain", null, null, null,
                                                                 null);

            domainSavant = new DomainCreatingSavant(decoratedSavant);
        }

        [TearDown]
        public void TearDown()
        {
            decoratedSavant.VerifyAllExpectations();
        }

        [Test]
        public void Delete()
        {
            var a = new A();
            ItemMapping mapping = ItemMapping.Create(typeof (A));

            // set mock expectations
            simpleDb.Expect(x => x.CreateDomain(null));
            decoratedSavant.Expect(x => x.DeleteAttributes(mapping, a.ItemName));

            domainSavant.DeleteAttributes(mapping, a.ItemName);
        }

        [Test]
        public void Get()
        {
            var a = new A();
            ItemMapping mapping = ItemMapping.Create(typeof (A));

            // set mock expectations
            simpleDb.Expect(x => x.CreateDomain(null));
            decoratedSavant.Expect(x => x.GetAttributes(mapping, a.ItemName)).Return(null);

            domainSavant.GetAttributes(mapping, a.ItemName);
        }

        [Test]
        public void Put()
        {
            var a = new A();
            PropertyValues values = PropertyValues.CreateValues(a);
            ItemMapping mapping = ItemMapping.Create(typeof (A));

            // set mock expectations
            simpleDb.Expect(x => x.CreateDomain(null));
            decoratedSavant.Expect(x => x.PutAttributes(mapping, values));

            domainSavant.PutAttributes(mapping, values);
        }

        [Test]
        [ExpectedException(typeof (WebException))]
        public void Put_NonAmazonError()
        {
            var a = new A();
            PropertyValues values = PropertyValues.CreateValues(a);
            ItemMapping mapping = ItemMapping.Create(typeof (A));

            // set mock expectations
            decoratedSavant.Expect(x => x.PutAttributes(mapping, values)).Throw(new WebException());

            domainSavant.PutAttributes(mapping, values);
        }

        /// <summary>
        /// Verify that domain is recreated on next attempt if deleted during processing.
        /// </summary>
        [Test]
        public void Put_DomainError()
        {
            var a = new A();
            PropertyValues values = PropertyValues.CreateValues(a);
            ItemMapping mapping = ItemMapping.Create(typeof(A));

            // set mock expectations
            simpleDb.Expect(x => x.CreateDomain(null)).Repeat.Twice();
            decoratedSavant.Expect(x => x.PutAttributes(mapping, values)).Throw(domainMissingException).Repeat.Once();
            decoratedSavant.Expect(x => x.PutAttributes(mapping, values));

            try
            {
                domainSavant.PutAttributes(mapping, values);
                Assert.Fail("Expected domain error");
            } catch (AmazonSimpleDBException)
            {
                // ignore
            }

            domainSavant.PutAttributes(mapping, values);
        }

        [Test]
        [ExpectedException(typeof (AmazonSimpleDBException))]
        public void Put_NonDomainError()
        {
            var a = new A();
            PropertyValues values = PropertyValues.CreateValues(a);
            ItemMapping mapping = ItemMapping.Create(typeof (A));

            // set mock expectations
            decoratedSavant.Expect(x => x.PutAttributes(mapping, values)).Throw(new AmazonSimpleDBException(""));

            domainSavant.PutAttributes(mapping, values);
        }

        [Test]
        public void Select()
        {
            var command = new SelectCommand(typeof (A), "select from A");

            // set mock expectations
            simpleDb.Expect(x => x.CreateDomain(null));
            decoratedSavant.Expect(x => x.SelectAttributes(command)).Return(null);

            domainSavant.SelectAttributes(command);
        }

        [Test]
        public void Select_Command()
        {
            var command = new SelectCommand<A>("select from A");
            // set mock expectations
            simpleDb.Expect(x => x.CreateDomain(null));
            decoratedSavant.Expect(x => x.SelectAttributes(command)).Return(null);

            domainSavant.SelectAttributes(command);
        }
    }
}